import string
import unicodedata
from urlparse import urlparse
from google.appengine.ext import ndb


@ndb.tasklet
def update_entity_async(entity):
    """
    Tasklet to asynchronously update an entity.
    """
    yield entity.put_async()

def shorten_url(url):
    """
    Helper function to create an abbreviated version of an URL that is suitable
    for display. The shortened URL is simply the network location plus "/..."
    if the URL has a path component. All other details (protocol, full path,
    parameters, etc.) are removed.
    """
    parsed = urlparse(url)
    short = parsed.netloc
    if parsed.path:
        short += "/..."
    return short

def all_unique_substrings(string, min_len=1):
    """
    Helper function to create a set of all (unique) substrings of a given
    string.
    """
    if min_len < 1:
        return []

    length = min_len
    subs = set()

    while length <= len(string):
        for start in range(len(string) - length + 1):
            subs.add(string[start:start + length])
        length += 1

    return subs

def create_search_terms(unicode_str):
    """
    Create a list of unique search terms from a given string. The list is built
    from the set of all substrings of all words in the given string. The string
    is first converted to lower-case, stripped of any punctuation characters,
    and accented characters are mapped to non-accented equivalents.
    """
    if not unicode_str:
        return []

    ascii_str = homogenize_name(unicode_str)

    # remove punctuation characters and split the remaining text into words
    words = string.translate(ascii_str, None, string.punctuation).split()

    # create search terms by listing all substrings of each word
    terms = set()
    for word in words:
        terms = terms.union(all_unique_substrings(word))

    return list(terms)

def prepare_search_args(unicode_str):
    """
    Prepare a list of unique search arguments from a given search string. The
    list is built from the set of all unique words in the given string. The
    string is first converted to lower-case, stripped of any punctuation
    characters, and accented characters are mapped to non-accented equivalents.
    """
    if not unicode_str:
        return []

    ascii_str = homogenize_name(unicode_str)

    # remove punctuation characters and split the remaining text into words
    words = string.translate(ascii_str, None, string.punctuation).split()

    # return a list of unique words
    return list(set(words))

def homogenize_name(unicode_str):
    """
    Convert an unicode string into an ASCII string mapping accented characters
    to non-accented equivalents and converting it to lower-case. This is useful
    for using strings in sorting and searchin.
    """
    if not unicode_str:
        return unicode_str

    # convert unicode string to ASCII converting letters to lower-case and
    # mapping accented characters to similar, non-accented ones
    return unicodedata.normalize('NFKD',
                                 unicode_str.lower()).encode('ASCII', 'ignore')
